home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 6 code / TCP / NewsWatcher / NW Source / Shared Code / Reusable Source / smtp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-26  |  6.7 KB  |  252 lines  |  [TEXT/MMCC]

  1. /*----------------------------------------------------------------------------
  2.  
  3.     smtp.c
  4.  
  5.     This reusable and reentrant module implements SMTP mail.
  6.     
  7.     The following functions are exported:
  8.     
  9.         SmtpOpen - Open an SMTP stream.
  10.         SmtpClose - Close an SMTP stream.
  11.         SmtpSendMessage - Send a mail message.
  12.         SmtpGetServerErrInfo - Get server error information.
  13.     
  14.     You must call memutil.c/InitMemUtil and net.c/NetInit before calling any of
  15.     the functions in this module. You also must call the NetIdle function in your
  16.     idle loop, and the NetTerm function at program termination.
  17.         
  18.     A "stream" is an abstraction representing a bidirectional network connection
  19.     to an SMTP server. A stream is represented as a variable of type "SmtpStreamRef". 
  20.     These stream references are opaque. You may copy them and pass them as parameters 
  21.     to functions in smtp.c, but you are prohibited from accessing the contents of
  22.     the memory blocks pointed to by the references. Only the functions in 
  23.     smtp.c are permitted to manipulate the contents of these blocks.
  24.     
  25.     The functions return a value of type OSErr as the function result:
  26.     
  27.         noErr                no error occurred
  28.         smtpServerErr        server error
  29.         other                any other OS or Toolbox error code
  30.         
  31.     If the function result is smtpServerErr, the SmtpGetServerErrInfo function can
  32.     be called to get information about the server error. On server errors, the 
  33.     stream is still allocated and open on return to the caller.
  34.         
  35.     If an OS or Toolbox error occurs, the stream is aborted and deallocated before
  36.     returning to the caller. "Aborted" means that the server connection is closed 
  37.     abruptly, without going through the usual TCP stream teardown process. You must 
  38.     perform careful error checking. The stream is deallocated, and must not be reused.
  39.     
  40.     Copyright © 1994-1995, Northwestern University.
  41.  
  42. ----------------------------------------------------------------------------*/
  43.  
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #include <stdio.h>
  47.  
  48. #include "def.h"
  49. #include "net.h"
  50. #include "smtp.h"
  51. #include "memutil.h"
  52.  
  53.  
  54.  
  55. /* Types. */
  56.  
  57. typedef struct TStream {
  58.     NetStreamRef netStream;                /* net stream reference */
  59.     Boolean needReset;                    /* true if must send RSET command before
  60.                                            next message */
  61. } TStream, *TStreamPtr, **TStreamHandle;
  62.  
  63.  
  64.  
  65. /*----------------------------------------------------------------------------
  66.     SmtpOpen 
  67.     
  68.     Open an SMTP stream.
  69.     
  70.     Entry:    host = server host address (domain name or dotted 
  71.                 decimal IP address).
  72.     
  73.     Exit:    function result = result code.
  74.             stream = reference to opened stream, 
  75.                 or nil if function result != noErr.
  76. ----------------------------------------------------------------------------*/
  77.  
  78. OSErr SmtpOpen (char *host, SmtpStreamRef *stream)
  79. {
  80.     TStreamHandle s = nil;
  81.     unsigned long addr;
  82.     unsigned short port;
  83.     NetStreamRef netStream;
  84.     CStr255 myName;
  85.     CStr255 command, response;
  86.     long responseCode;
  87.     OSErr err = noErr;
  88.     
  89.     err = MyNewHandle(sizeof(TStream), &s);
  90.     if (err != noErr) return err;
  91.  
  92.     err = NetNameToAddr(host, kSMTPPort, &addr, &port);
  93.     if (err != noErr) goto exit;
  94.     
  95.     err = NetOpen(addr, port, true, &netStream, &responseCode, response);
  96.     if (err != noErr) goto exit;
  97.  
  98.     (**s).netStream = netStream;
  99.     (**s).needReset = false;
  100.     *stream = (SmtpStreamRef)s;
  101.     
  102.     if (responseCode != 220) return smtpServerErr;
  103.     
  104.     err = NetGetMyName(myName);
  105.     if (err != noErr) {
  106.         err = NetGetMyAddrStr(myName);
  107.         if (err != noErr) {
  108.             NetClose(netStream);
  109.             goto exit;
  110.         }
  111.     }
  112.     sprintf(command, "HELO %.250s", myName);
  113.     err = NetCommand(netStream, command, &responseCode, response);
  114.     if (err != noErr) goto exit;
  115.     if (responseCode != 250) return smtpServerErr;
  116.  
  117.     return noErr;
  118.     
  119. exit:
  120.  
  121.     MyDisposeHandle(s);
  122.     return err;
  123. }
  124.  
  125.  
  126.  
  127. /*----------------------------------------------------------------------------
  128.     SmtpClose 
  129.     
  130.     Close an SMTP stream.
  131.     
  132.     Entry:    stream = stream reference.
  133.     
  134.     Exit:    function result = result code.
  135. ----------------------------------------------------------------------------*/
  136.  
  137. OSErr SmtpClose (SmtpStreamRef stream)
  138. {
  139.     TStreamHandle s;
  140.     OSErr err = noErr;
  141.     
  142.     s = (TStreamHandle)stream;
  143.     err = NetClose((**s).netStream);
  144.     MyDisposeHandle(s);
  145.     return err;
  146. }
  147.  
  148.  
  149.  
  150. /*----------------------------------------------------------------------------
  151.     SmtpSendMessage 
  152.     
  153.     Send a mail message.
  154.     
  155.     Entry:    stream = stream reference.
  156.             from = C-format email address of sender.
  157.             to = C-format email address of recipient.
  158.             text = handle to message text, including SMTP header, with CR line 
  159.                 terminators. Warning: the memory block is modified by the function.
  160.                 The memory block must be unlocked and nonpurgeable.
  161.     
  162.     Exit:    function result = result code.
  163.     
  164.     Multiple recipients may be listed in the "to" string, separated by commas.
  165. ----------------------------------------------------------------------------*/
  166.  
  167. OSErr SmtpSendMessage (SmtpStreamRef stream, char *from, char *to, Handle text)
  168. {
  169.     TStreamHandle s;
  170.     NetStreamRef netStream;
  171.     char *p, *q;
  172.     short len;
  173.     CStr255 command, response;
  174.     long responseCode;
  175.     OSErr err = noErr;
  176.     
  177.     s = (TStreamHandle)stream;
  178.     netStream = (**s).netStream;
  179.     
  180.     if ((**s).needReset) {
  181.         strcpy(command, "RSET");
  182.         err = NetCommand(netStream, command, &responseCode, response);
  183.         if (err != noErr) goto exit1;
  184.         if (responseCode != 250) goto exit2;
  185.         (**s).needReset = false;
  186.     }
  187.     
  188.     sprintf(command, "MAIL FROM:<%.243s>", from);
  189.     err = NetCommand(netStream, command, &responseCode, response);
  190.     if (err != noErr) goto exit1;
  191.     if (responseCode != 250) goto exit2;
  192.     
  193.     p = to;
  194.     while (*p != 0) {
  195.         q = p;
  196.         while (*q != 0 && *q != ',') q++;
  197.         len = q-p;
  198.         if (len > 0 && len <= 245) {
  199.             sprintf(command, "RCPT TO:<%.*s>", len, p);
  200.             err = NetCommand(netStream, command, &responseCode, response);
  201.             if (err != noErr) goto exit1;
  202.             if (responseCode != 250 && responseCode != 251) goto exit2;
  203.         }
  204.         p = q;
  205.         if (*p == ',') p++;
  206.     }
  207.     
  208.     strcpy(command, "DATA");
  209.     err = NetCommand(netStream, command, &responseCode, response);
  210.     if (err != noErr) goto exit1;
  211.     if (responseCode != 354) goto exit2;
  212.     
  213.     err = NetPutText(netStream, text);
  214.     if (err != noErr) goto exit1;
  215.     
  216.     err = NetGetExtraResponse(netStream, &responseCode, response);
  217.     if (err != noErr) goto exit1;
  218.     if (responseCode != 250 && responseCode != 251) goto exit2;
  219.     
  220.     return noErr;
  221.     
  222. exit1:
  223.  
  224.     MyDisposeHandle(s);
  225.     return err;
  226.     
  227. exit2:
  228.  
  229.     (**s).needReset = true;
  230.     return smtpServerErr;
  231. }
  232.  
  233.  
  234.  
  235. /*----------------------------------------------------------------------------
  236.     SmtpGetServerErrInfo 
  237.     
  238.     Get server error information.
  239.     
  240.     Entry:    stream = stream reference.
  241.     
  242.     Exit:    *serverErrInfo = server error information.
  243. ----------------------------------------------------------------------------*/
  244.  
  245. void SmtpGetServerErrInfo (SmtpStreamRef stream, NetServerErrInfo *serverErrInfo)
  246. {
  247.     TStreamHandle s;
  248.     
  249.     s = (TStreamHandle)stream;
  250.     NetGetServerErrInfo((**s).netStream, serverErrInfo);
  251. }
  252.